// Copyright 2022 jeff.li. and/or its affiliates.

#pragma once

#include <tbir/runtime/container/list_ref.h>
#include <tbir/runtime/container/string.h>
#include <tbir/runtime/container/tuple_ref.h>
#include <tbir/runtime/container/unicode.h>
#include <tbir/runtime/global_type_index.h>
#include <tbir/runtime/object.h>
#include <tbir/runtime/runtime_value.h>

namespace tbir::runtime {

    class RegexNode;

    class Regex : public ObjectRef {
    public:
        using ContainerType = RegexNode;
        static constexpr bool _type_is_nullable = false;  // disable nullptr for performance

        Regex(const unicode_view &pattern,
              bool ignore_case,
              bool dotall,
              bool extended,
              bool anchored,
              bool ucp)
                : Regex(UnicodeHelper::Encode(pattern), ignore_case, dotall, extended, anchored, ucp) {
        }

        Regex(const string_view &pattern,
              bool ignore_case,
              bool dotall,
              bool extended,
              bool anchored,
              bool ucp);

        Regex(const Any &pattern, bool ignore_case, bool dotall, bool extended, bool anchored, bool ucp);

        Regex() = default;

        Regex(Regex &&other) noexcept = default;

        Regex(const Regex &other) noexcept = default;

        Regex &operator=(Regex &&other) noexcept = default;

        Regex &operator=(const Regex &other) noexcept = default;

        /*!
         * \brief constructor from pointer
         * \param n the container pointer
         */
        explicit Regex(ObjectPtr <Object> n) noexcept: ObjectRef(std::move(n)) {
        }

        const RegexNode *operator->() const;

        const RegexNode *get() const;

        List split(const string_view &input) const;

        List split(const unicode_view &input) const;

        List split(const Any &input) const;

        String replace(const string_view &input, const string_view &repl) const;

        inline String replace(const string_view &input, const Any &repl) const {
            return replace(input, repl.As<string_view>());
        }

        inline String replace(const Any &input, const string_view &repl) const {
            return replace(input.As<string_view>(), repl);
        }

        Unicode replace(const unicode_view &input, const unicode_view &repl) const;

        Unicode replace(const unicode_view &input, const Any &repl) const {
            return replace(input, repl.As<unicode_view>());
        }

        Unicode replace(const Any &input, const unicode_view &repl) const {
            return replace(input.As<unicode_view>(), repl);
        }

        RTValue replace(const Any &input, const Any &repl) const;

        Tuple match(const string_view &input, int64_t offset = 0) const;

        Tuple match(const unicode_view &input, int64_t offset = 0) const;

        Tuple match(const Any &input, int64_t offset = 0) const;
    };

    template<>
    bool IsConvertible<Regex>(const Object *node);

    namespace TypeIndex {
        template<>
        struct type_index_traits<Regex> {
            static constexpr int32_t value = kRuntimeRegex;
        };
    }  // namespace TypeIndex

}  // namespace tbir::runtime
